package com.alks.function.service.impl.stockdept.pcfactorystockquery;

import com.alks.common.data.dto.SysUserTokenDTO;
import com.alks.common.data.thread.UserIdThread;
import com.alks.common.service.RedisService;
import com.alks.common.utils.beanutils.ArrayUtils;
import com.alks.common.utils.beanutils.BeanUtil;
import com.alks.entity.data.entity.PcSlipTemp;
import com.alks.entity.data.entity.PcSurplusDetail;
import com.alks.entity.data.entity.PcSurplusTemp;
import com.alks.entity.data.response.ResponseInfo;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.OMtlInDto;
import com.alks.function.data.dto.stockdept.pcfactorystockwork.OtMtlOutDto;
import com.alks.function.data.request.stockdept.pcfactorystockwork.MOSDetAddRequest;
import com.alks.function.data.request.stockdept.pcfactorystockwork.OMtlWatiRequest;
import com.alks.function.data.request.stockdept.pcfactorystockwork.OMtlwaitAddRequest;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcLotUsageMapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcMtlAccMapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcSurplusDetailMapper;
import com.alks.function.mapper.stockdept.pcfactorystockquery.SD_SQ_PcSurplusTempMapper;
import com.alks.function.service.stockdept.pcfactorystockquery.IMtlOutSurpService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.alks.entity.data.enums.ResultCodeEnum.DATA_IS_ERR;
import static com.alks.entity.data.enums.ResultCodeEnum.INPUT_ERROR;

@Service
@Slf4j
@RequiredArgsConstructor
public class MtlOutSurpServiceImpl extends ServiceImpl<SD_SQ_PcSurplusTempMapper, PcSurplusTemp> implements IMtlOutSurpService {
    private final SD_SQ_PcSurplusDetailMapper detailMapper;
    private final SD_SQ_PcSurplusTempMapper tempMapper;
    private final SD_SQ_PcLotUsageMapper usageMapper;
    private final SD_SQ_PcMtlAccMapper accMapper;
    private final RedisService redisService;

    @Override
    public ResponseInfo getMOSTempQuery() {
        /*获取数据*/
        List<PcSurplusTemp> temps = lambdaQuery()
                .eq(PcSurplusTemp::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSurplusTemp::getSlipType, "O").list();
        /*提取数据*/
        List<OtMtlOutDto> dtos = BeanUtil.copyList(temps, OtMtlOutDto.class);
        return ResponseInfo.ok(dtos);
    }

    @Override
    public ResponseInfo mOSTempUpdate(String mtlNo, Float qty, String remark) {
        /*更新数据*/
        lambdaUpdate().set(PcSurplusTemp::getQty, qty)
                .set(PcSurplusTemp::getRemark, remark)
                .eq(PcSurplusTemp::getMtlNo, mtlNo)
                .eq(PcSurplusTemp::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSurplusTemp::getSlipType, "O").update();
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo mOSTempAdd(List<OMtlwaitAddRequest> request, Integer type) {
        /*判断材料是否已存在*/
        List<String> mtlNos = request.stream().map(OMtlwaitAddRequest::getMtlNo).collect(Collectors.toList());
        LambdaQueryWrapper<PcSurplusTemp> wrapper = new LambdaQueryWrapper<PcSurplusTemp>()
                .select(PcSurplusTemp::getMtlName)
                .eq(PcSurplusTemp::getSlipType, "O")
                .eq(PcSurplusTemp::getSysUser, UserIdThread.get().getLoginName())
                .in(PcSurplusTemp::getMtlNo, mtlNos);
        List<PcSurplusTemp> temps = tempMapper.selectList(wrapper);
        if (temps != null && !temps.isEmpty() && temps.get(0).getMtlName() != null) {
            return ResponseInfo.ok("存在重复物料：" + temps.get(0).getMtlName());
        }
        /*获取数据*/
        List<PcSlipTemp> slipTemps = new ArrayList<>();
        switch (type) {
            case 1:
                slipTemps = accMapper.getOtMtlWaitStk2(request);
                break;
            case 2:
                slipTemps = usageMapper.getOtMtlWaitStk2(request);
                break;
        }
        /*判断数据是否存在*/
        if (slipTemps == null || slipTemps.isEmpty()) {
            log.error("请求方法：mTSTempAdd\n错误原因：没有找到数据\n请求参数：mtlNo:{},type:{}",
                    request.get(0).getMtlNo(), type);
            return ResponseInfo.error("数据异常，请重试", DATA_IS_ERR.getCode());
        }
        /*写入数据*/
        tempMapper.mOSTempAdd(slipTemps, UserIdThread.get().getLoginName());
        return ResponseInfo.ok("写入成功");
    }

    @Override
    public ResponseInfo getMOSDetailQuery(OMtlWatiRequest request) {
        /*获取数据*/
        LambdaQueryWrapper<PcSurplusDetail> wrapper = new LambdaQueryWrapper<PcSurplusDetail>()
                .eq(PcSurplusDetail::getSysUser, UserIdThread.get().getLoginName())
                .eq(PcSurplusDetail::getSlipType, "O")
                .eq(request.getSlipNo() != null && !request.getSlipNo().isEmpty(), PcSurplusDetail::getSlipNo, request.getSlipNo())
                .eq(request.getSlipReason() != null && !request.getSlipReason().isEmpty(), PcSurplusDetail::getSlipReason, request.getSlipReason())
                .ge(request.getSlipDateStart() != null, PcSurplusDetail::getSlipDate, request.getSlipDateStart())
                .le(request.getSlipDateEnd() != null, PcSurplusDetail::getSlipDate, request.getSlipDateEnd());
        List<PcSurplusDetail> details = detailMapper.selectList(wrapper);
        /*提取数据*/
        List<OMtlInDto> dtos = BeanUtil.copyList(details, OMtlInDto.class);
        return ResponseInfo.ok(dtos);
    }

    @Override
    @Transactional
    public ResponseInfo mOSDetailAdd(MOSDetAddRequest request) {
        SysUserTokenDTO tokenDTO = UserIdThread.get();
        String companyId = tokenDTO.getCompanyId();
        /*获取数据*/
        LambdaQueryWrapper<PcSurplusTemp> tempWrapper = new LambdaQueryWrapper<PcSurplusTemp>()
                .eq(PcSurplusTemp::getCompanyId, companyId)
                .eq(PcSurplusTemp::getSysUser, tokenDTO.getLoginName())
                .eq(PcSurplusTemp::getSlipType, "O")
                .isNotNull(PcSurplusTemp::getQty)
                .ne(PcSurplusTemp::getQty, 0);
        List<PcSurplusTemp> temps = tempMapper.selectList(tempWrapper);
        /*核验数据*/
        if (ArrayUtils.isEmpyt(temps)) {
            log.warn("异常接口：mOSDetailAdd\n异常原因：待出库明细中没有数量大于0的数据，无法出库批处理");
            return ResponseInfo.error("没有出库数量大于0的数据", INPUT_ERROR.getCode());
        }
        /*核验库存*/
        List<String> tempMtls = temps.stream().map(PcSurplusTemp::getMtlNo).collect(Collectors.toList());
        List<Map<String, Object>> stkDetails = detailMapper.stkQueryByMtlNos(tempMtls, companyId);
        Map<String, BigDecimal> detailsQty = stkDetails.stream().filter(Objects::nonNull)
                .collect(Collectors.toMap(a -> (String) a.get("mtlNo"), a -> (BigDecimal) a.get("qty")));
        for (PcSurplusTemp temp : temps) {
            if (BigDecimal.valueOf(temp.getQty()).compareTo(detailsQty.get(temp.getMtlNo())) < 0) {
                log.warn("异常接口：mOSDetailAdd\n异常原因：库存不足，无法出库 mtlNo:{}", temp.getMtlNo());
                return ResponseInfo.error("有材料库存不足，材料ID为" + temp.getMtlNo());
            }
        }
        /*生成订单号*/
        String slipNo = redisService.slipNoCreat("E");
        /*写入数据*/
        List<PcSurplusDetail> details = BeanUtil.copyList(temps, PcSurplusDetail.class);
        for (PcSurplusDetail detail : details) {
            detail.setSlipReason(request.getSlipReason());
            detail.setDeptNo(request.getDeptNo());
            detail.setDeptName(request.getDeptName());
            detail.setSlipDate(request.getSlipDate() == null ? LocalDateTime.now() : request.getSlipDate().atStartOfDay());
            detail.setSlipNo(slipNo);
            detail.setItem(1);
            detail.setSysUser(tokenDTO.getUserName());
            detail.setSysDate(LocalDateTime.now());
            detailMapper.insert(detail);
        }
        /*删除库存数据*/
        tempMapper.delete(tempWrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo mOSTempDelete(String mtlNo) {
        LambdaQueryWrapper<PcSurplusTemp> wrapper = new LambdaQueryWrapper<PcSurplusTemp>()
                .eq(PcSurplusTemp::getMtlNo, mtlNo)
                .eq(PcSurplusTemp::getSlipType, "O")
                .eq(PcSurplusTemp::getSysUser, UserIdThread.get().getLoginName());
        tempMapper.delete(wrapper);
        return ResponseInfo.ok();
    }

    @Override
    public ResponseInfo mOSDetailDelete(String mtlNo, String slipNo) {
        LambdaQueryWrapper<PcSurplusDetail> wrapper = new LambdaQueryWrapper<PcSurplusDetail>()
                .eq(PcSurplusDetail::getMtlNo, mtlNo)
                .eq(PcSurplusDetail::getSlipNo, slipNo)
                .eq(PcSurplusDetail::getSlipType, "O")
                .eq(PcSurplusDetail::getSysUser, UserIdThread.get().getLoginName());
        detailMapper.delete(wrapper);
        return ResponseInfo.ok();
    }
}
